
import os
import sys

# print(sys.path)
# 由于本脚本在 tests 目录，任何情况下将只以此脚本所在目录为根目录
# 如果是使用 python3 运行此脚本，确保在编译器的时候加入当前目录(确保在项目目录下)
sys.path.append(os.path.abspath(".")) 
# 如果是使用 Code Runner 插件运行此脚本，确保在 cd <paths>/test 的时候加入父级目录
sys.path.append(os.path.abspath("..")) 
sys.path.append(os.path.abspath("../..")) 
# print(sys.path)

from PyQt5.QtGui import QPixmap

import project.resources
from project.base import *

# MainWindow 一个来自 mainwindow.ui 的
from ui_mainwindow import Ui_MainWindow


# Explicit and implicit alternation
# 动画线程
class AnimationThread(QObject): 
    # 定义信号
    finished = pyqtSignal()
    changed = pyqtSignal(float)

    timeout: int = 1000
    timer: QTimer
    
    begin: float = 0
    end: float = 10
    step: float = 1
    tc: float = 0
    reverse: bool = False
    
    def __init__(self, parent=None):
        super(AnimationThread, self).__init__(parent)
        self.timer = QTimer(self)
        self.timer.timeout.connect(lambda : self.changed.emit(self.tc + self.step))
        self.changed.connect(self.clokcChanged)
        self.changed.connect(lambda x: print(self.objectName() ,":", x))

    def setRange(self, begin, end, step, reverse=False):
        self.begin = begin
        self.end = end
        self.step = step
        self.reverse = reverse
        if self.reverse:
            self.step = -self.step
        
    def setDuration(self, msecs):
        self.timeout = msecs

    def start(self):
        self.tc = self.begin
        if self.reverse:
            self.tc = self.end
        self.timer.setInterval(self.timeout / abs((self.end - self.begin) / self.step))
        self.timer.start()

    def clokcChanged(self, x):
        self.tc = x
        if (self.reverse and self.tc < self.begin) or self.tc >= self.end:
            self.timer.stop()
            self.finished.emit()

# 显隐交替动画，在一定时间内进行播放动效
#   动画线程A隐： 从 1 -> 0.1
#   动画线程B显： 从 0.1 -> 1
# 1. A发出完成信号时B启动
# 2. B发出完成信号时计次，并再启动A
# 3. 在计数达成时不再启动A
class EmergeAnimation():
    finished = pyqtSignal()
    
    goe: QGraphicsOpacityEffect
    target: QWidget
    times: int = 2
    tc: int = 0
    
    def __init__(self, parent: QWidget):
        self.goe = QGraphicsOpacityEffect()
        self.goe.setOpacity(1)
        
        self.target = parent
        self.target.setGraphicsEffect(self.goe)
        
        self.at = AnimationThread()
        self.at.setObjectName("at")
        self.at2 = AnimationThread()
        self.at2.setObjectName("at2")
        
    def setTimes(self, times):
        self.times = times
        
    def setDuration(self, msecs):
        self.at.setDuration(msecs)
        self.at2.setDuration(msecs)

    def start(self):
        self.tc = 0
        begin, end, step = 0.1, 0.7, 0.001
        
        self.at.setRange(begin, end, step, True)
        self.at.changed.connect(lambda x : self.changeGeo(x))
        
        self.at2.setRange(begin, end, step)
        self.at2.changed.connect(lambda x : self.changeGeo(x))
        
        self.at.finished.connect(self.at2.start)
        self.at2.finished.connect(self.resumeTc)
        self.at.start()

    def resumeTc(self):
        self.tc = self.tc + 1 
        if self.tc < self.times:
            self.at.start()
        
        
    @pyqtSlot()
    def changeGeo(self, x:float):
        print("changeGeo:", x)
        self.goe.setOpacity(x)
        self.target.setGraphicsEffect(self.goe)

# 抖动动画
class ShakeAnimation():
    
    target: QWidget
    
    def __init__(self, parent=QWidget):
        self.target = parent
        
    def start(self):
        shakeBtn = self.target
        
        x = shakeBtn.x()
        y = shakeBtn.y()
        shakeBtnPoint = QPoint(x,y)
        shakeBtnSize = shakeBtn.size()
        shakeBtnRect = QRect(shakeBtnPoint, shakeBtnSize)
        
        # 使用动画来操作目标的属性
        animation = QPropertyAnimation(shakeBtn, b"geometry", shakeBtn)
        animation.setEasingCurve(QEasingCurve.Type.InOutSine)
        animation.setDirection(400)
        animation.setStartValue(shakeBtnRect)
        animation.setEndValue(shakeBtnRect)
        
        # 定义抖动幅度、以及次数和单步数值比例计算
        shakeRange = 10     # 我们将其固定(也许可以使用传参形式)
        shakeCount = 8      # 我们将其固定抖动次数为8次
        shakeStep = 1.0/shakeCount  # 我们将计算步值，用于 setKeyValueAt 使用的 0-1 之间的步值
        for i in range(1, shakeCount): 
            shakeRange = -shakeRange
            animation.setKeyValueAt(shakeStep * i, QRect(QPoint(x + shakeRange, y), shakeBtnSize))
        animation.start(QAbstractAnimation.DeletionPolicy.DeleteWhenStopped)
        
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        
        # from widget import LmLmAnimation
        # LmLmAnimation()
        # a = Animation()
        # a.setTarget(self.ui.pushButton)
        # a.finished.connect(lambda: print("animation"))
        # a.start()
        
        self.ui.label.setText("测试 Animation 窗口")
        self.setWindowTitle(self.ui.label.text())
        
        # at = AnimationThread()
        # at.changed.connect(lambda x: print("changed:", x))
        # at.setRange(1,5,0.1)
        # at.start()
        
        
    @pyqtSlot()
    def on_pushButton_clicked(self):
        ShakeAnimation(self.ui.pushButton).start()
        ea = EmergeAnimation(self.ui.label)
        # ea.setTimes(3)
        # ea.setDuration(1000)
        ea.start()
        

# 一个动画居中窗口
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    moveWidgetCenterInDesktopWidget(window)
    sys.exit(app.exec_())
